/*
 * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
 *
 * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
 *
 * Use of this source code is governed by MIT-like license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
 */

#include <signal.h>
#include <string.h>
#include <stdio.h>
#include "unistd.h"
#include "mk_mediakit.h"
#include <pthread.h>

#define LOG_LEV 4
 // 修改此宏，可以选择协议类型  [AUTO-TRANSLATED:7a3e6a3a]
 // Modify this macro to choose the protocol type
#define TCP_TYPE mk_type_ws

////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct {
    mk_tcp_session _session;
    // 下面你可以夹杂你的私货数据  [AUTO-TRANSLATED:99451203]
    // You can insert your private data below
    char your_some_useful_data[1024];
} tcp_session_user_data;


typedef struct WsSessionNode {
    tcp_session_user_data *data;
    struct WsSessionNode *next;
} WsSessionNode;

static WsSessionNode *wssessionlist_ = NULL;
static pthread_mutex_t session_mutex = PTHREAD_MUTEX_INITIALIZER;
/**
 * 当tcp客户端连接服务器时触发
 * @param session 会话处理对象
 * Triggered when the tcp client connects to the server
 * @param session Session processing object

 * [AUTO-TRANSLATED:0030d1a6]
 */
void API_CALL on_mk_tcp_session_create(uint16_t server_port, mk_tcp_session session) {
    char ip[64];
    log_printf(LOG_LEV, "%s %d", mk_tcp_session_peer_ip(session, ip), (int)mk_tcp_session_peer_port(session));
    tcp_session_user_data* user_data = (tcp_session_user_data*)malloc(sizeof(tcp_session_user_data));
    user_data->_session = session;
    mk_tcp_session_set_user_data(session, user_data);
    WsSessionNode *new_node = (WsSessionNode *)malloc(sizeof(WsSessionNode));
    new_node->data = user_data;
    pthread_mutex_lock(&session_mutex);
    new_node->next = wssessionlist_;
    wssessionlist_ = new_node;
    pthread_mutex_unlock(&session_mutex);
}

/**
 * 收到tcp客户端发过来的数据
 * @param session 会话处理对象
 * @param data 数据指针
 * @param len 数据长度
 * Receive data sent from the tcp client
 * @param session Session processing object
 * @param data Data pointer
 * @param len Data length

 * [AUTO-TRANSLATED:f8f01265]
 */
void API_CALL on_mk_tcp_session_data(uint16_t server_port, mk_tcp_session session, mk_buffer buffer) {
    char ip[64];
    log_printf(LOG_LEV, "from %s %d, data[%d]: %s",
        mk_tcp_session_peer_ip(session, ip),
        (int)mk_tcp_session_peer_port(session),
        mk_buffer_get_size(buffer),
        mk_buffer_get_data(buffer));
    // mk_tcp_session_send(session, "echo:", 0);
    // mk_tcp_session_send_buffer(session, buffer);
}

/**
 * 每隔2秒的定时器，用于管理超时等任务
 * @param session 会话处理对象
 * Timer every 2 seconds, used to manage timeout tasks
 * @param session Session processing object

 * [AUTO-TRANSLATED:f664481f]
 */
void API_CALL on_mk_tcp_session_manager(uint16_t server_port, mk_tcp_session session) {
    char ip[64];
    log_printf(LOG_LEV, "%s %d", mk_tcp_session_peer_ip(session, ip), (int)mk_tcp_session_peer_port(session));
}

/**
 * 一般由于客户端断开tcp触发
 * 本事件中可以调用mk_tcp_session_send_safe函数
 * @param session 会话处理对象
 * @param code 错误代码
 * @param msg 错误提示
 * Generally triggered by the client disconnecting tcp
 * You can call the mk_tcp_session_send_safe function in this event
 * @param session Session processing object
 * @param code Error code
 * @param msg Error message

 * [AUTO-TRANSLATED:62628263]
 */
void API_CALL on_mk_tcp_session_disconnect(uint16_t server_port, mk_tcp_session session, int code, const char* msg) {

    char ip[64];
    log_printf(LOG_LEV, "%s %d: %d %s", mk_tcp_session_peer_ip(session, ip), (int)mk_tcp_session_peer_port(session), code, msg);
    tcp_session_user_data* user_data = (tcp_session_user_data*)mk_tcp_session_get_user_data(session);

    pthread_mutex_lock(&session_mutex);
    WsSessionNode **curr = &wssessionlist_;
    while (*curr) {
        if ((*curr)->data == user_data) {
            WsSessionNode *to_free = *curr;
            *curr = (*curr)->next;
            free(to_free);
            break;
        }
        curr = &(*curr)->next;
    }
    pthread_mutex_unlock(&session_mutex);
    free(user_data);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Ws_server(int port) {
    mk_tcp_session_events events_server = {
            .on_mk_tcp_session_create = on_mk_tcp_session_create,
            .on_mk_tcp_session_data = on_mk_tcp_session_data,
            .on_mk_tcp_session_manager = on_mk_tcp_session_manager,
            .on_mk_tcp_session_disconnect = on_mk_tcp_session_disconnect
    };

    mk_tcp_server_events_listen(&events_server);
    mk_tcp_server_start(port, TCP_TYPE);
}

void Zl_SendWebsockString(const char* data, int size)
{
    pthread_mutex_lock(&session_mutex);
    WsSessionNode *current = wssessionlist_;
    while (current != NULL) {
        mk_tcp_session_send_safe(current->data->_session, data, size);
        current = current->next;
    }
    pthread_mutex_unlock(&session_mutex);
}
